//----------------------------------------------------------------------------------------------
//	Filename:	PointCloudSceneLoader.cpp
//	Author:		Sandro Spina
//	Date:		03/08/2012
//----------------------------------------------------------------------------------------------
//  Notes:	The PointCloud Scene loader is still partly based on the WavefrontSceneLoader... the 
//			material file is identical to .obj support material files (.mtl). Some day I will 
//			have to encode material files too in some binary format and rewrite this loader.
//----------------------------------------------------------------------------------------------
#include <iostream>
#include <fstream>
#include <string>
#include <map>

#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#include <Renderer\ScanRenderer.h>
#include <Integrator\DepthIntegrator.h>
#include <Device\NullDevice.h>
#include <Device\BufferedImageDevice.h>
#include <Sampler\RandomSampler.h>
#include <Maths\Montecarlo.h>

#include "Scene/Environment.h"
#include "Scene/PointCloudSceneLoader.h"
#include "Shape/KDTreePointCloud.h"
#include "Shape/LineWorldShapeForge.h"
#include "Shape/PlanarWorldShapeForge.h"

using namespace Illumina::Core;

struct PointCloudContext
{
	IPointCloud *PointCloud;	
	std::string ObjectName;	
	
	PointCloudContext(void)
		: PointCloud(NULL)		
	{ }
};

PointCloudSceneLoader::PointCloudSceneLoader(Environment *p_pEnvironment)
	: ISceneLoader(p_pEnvironment)
{ 
	BOOST_ASSERT(p_pEnvironment != NULL);
	m_pEngineKernel = p_pEnvironment->GetEngineKernel();
}

//----------------------------------------------------------------------------------------------
bool PointCloudSceneLoader::Import(const std::string &p_strFilename, unsigned int p_uiGeneralFlags, ArgumentMap* p_pArgumentMap)
{
	// Provide context for loader
	PointCloudContext context;

	float density, radius, scale, min_dst, max_dst, kNNFloodRadius, kNNTypeRadius, cornerRatioEpsilon, coplanarDst;
	int surfaces, models, kNNType, kNNFlood, kNNTypeMode, kNNFloodMode, edgeCornerDetect, scans, pcs_id;
	float curvature, noise, ballRadius;

	std::string pointcloudType;			
	p_pArgumentMap->GetArgument("Seed", pointcloudType);	//Either PWPC (Forge), OBJ or PCS
	boost::trim(pointcloudType);

	if (pointcloudType.compare("NULL")==0) return false;

	std::vector<std::string> tr;
	p_pArgumentMap->GetArgument("TrunkName", tr);
	pcs_id=boost::lexical_cast<int, std::string>(tr[1]);	
	p_pArgumentMap->GetArgument("Radius", radius);
	p_pArgumentMap->GetArgument("Scale", scale);
	p_pArgumentMap->GetArgument("Curvature", curvature);
	p_pArgumentMap->GetArgument("kNNType", kNNType);
	p_pArgumentMap->GetArgument("kNNFlood", kNNFlood);
	p_pArgumentMap->GetArgument("kNNTypeRadius", kNNTypeRadius);
	p_pArgumentMap->GetArgument("kNNFloodRadius", kNNFloodRadius);
	p_pArgumentMap->GetArgument("CornerRatioEps", cornerRatioEpsilon);
	p_pArgumentMap->GetArgument("EdgeCornerDetect", edgeCornerDetect);
	p_pArgumentMap->GetArgument("kNNTypeMode", kNNTypeMode);
	p_pArgumentMap->GetArgument("kNNFloodMode", kNNFloodMode);
	p_pArgumentMap->GetArgument("MinDistance", min_dst);
	p_pArgumentMap->GetArgument("MaxDistance", max_dst);
	p_pArgumentMap->GetArgument("Noise", noise);	
	p_pArgumentMap->GetArgument("EdgeCornerDetectR", ballRadius);
	p_pArgumentMap->GetArgument("SceneScan", scans);
	p_pArgumentMap->GetArgument("CoplanarDst", coplanarDst);
	
	if (pointcloudType.compare("LWPC")==0)
	{				
		//Generate a random LinesWorld Point Cloud		
		p_pArgumentMap->GetArgument("Density", density);
		p_pArgumentMap->GetArgument("SurfaceCount", surfaces);
		p_pArgumentMap->GetArgument("ModelCount", models);
		GenerateLWPCGeometry(context, density, radius, scale, surfaces, kNNType, kNNFlood, kNNTypeRadius, kNNFloodRadius);
	}
	 
	if (pointcloudType.compare("PWPC")==0)
	{	
		//Generate a random PlanarWorld Point Cloud
		p_pArgumentMap->GetArgument("SurfaceCount", surfaces);
		p_pArgumentMap->GetArgument("ModelCount", models);			
		GeneratePWPCGeometry(context, min_dst, max_dst, radius, scale, surfaces, curvature, cornerRatioEpsilon, kNNType, kNNFlood, kNNTypeRadius, kNNFloodRadius, kNNTypeMode, kNNFloodMode, edgeCornerDetect, noise);		
	}
	
	if (pointcloudType.compare("BLAB")==0)
	{
		if (!LoadBLABPoints(p_strFilename, context, min_dst, max_dst, radius, scale, curvature, cornerRatioEpsilon, kNNType, kNNFlood, kNNTypeRadius, kNNFloodRadius, kNNTypeMode, kNNFloodMode, edgeCornerDetect, noise, coplanarDst))
				return false;		
	}

	if (pointcloudType.compare("OBJ")==0)
	{
		// Load geometry (set of points) from file
		if (scans > 0)
		{
			//Flag a switch to indicate that we need to load this once the environment is up. Then scan the scene
			if (!LoadOBJGeometry(p_strFilename, context, min_dst, max_dst, radius, scale, curvature, cornerRatioEpsilon, kNNType, kNNFlood, kNNTypeRadius, kNNFloodRadius, kNNTypeMode, kNNFloodMode, edgeCornerDetect, noise, scans))
				return false;
		}
		else
		{
			if (!LoadOBJGeometry(p_strFilename, context, min_dst, max_dst, radius, scale, curvature, cornerRatioEpsilon, kNNType, kNNFlood, kNNTypeRadius, kNNFloodRadius, kNNTypeMode, kNNFloodMode, edgeCornerDetect, noise))
				return false;		
		}
	}

	if (pointcloudType.compare("PCS")==0)
	{	
		// Load geometry (set of points) from file
		if (!LoadPCSGeometry(p_strFilename, context, min_dst, max_dst, radius, scale, curvature, cornerRatioEpsilon, kNNType, kNNFlood, kNNTypeRadius, kNNFloodRadius, kNNTypeMode, kNNFloodMode, edgeCornerDetect, noise, coplanarDst))
			return false;		
	}

	if (pointcloudType.compare("ASC")==0)
	{	
		// Load geometry (set of points) from file
		if (!LoadASCGeometry(p_strFilename, context, min_dst, max_dst, radius, scale, curvature, cornerRatioEpsilon, kNNType, kNNFlood, kNNTypeRadius, kNNFloodRadius, kNNTypeMode, kNNFloodMode, edgeCornerDetect, noise, coplanarDst))
			return false;		
	}

	if (context.PointCloud != NULL)
	{		
		std::string pointCloudName = context.PointCloud->GetName();
		context.PointCloud->SetRadius(radius);
		context.PointCloud->SetBallRadius(ballRadius);
		context.PointCloud->SetPCSId(pcs_id);
		context.PointCloud->SetEnvironment(m_pEnvironment);
		
		if (p_pArgumentMap != NULL) 
			p_pArgumentMap->GetArgument("Id", pointCloudName);

		if (p_pArgumentMap->ContainsArgument("DiscardPoints"))
		{
			std::vector<std::string> discard_types;
			p_pArgumentMap->GetArgument("DiscardPoints", discard_types);		
			for (std::vector<std::string>::iterator dii = discard_types.begin(); dii != discard_types.end(); dii++)
			{				
				context.PointCloud->AddPointTypesToPrune(boost::lexical_cast<int,std::string>(*dii));
			}
		}
		
		m_pEngineKernel->GetShapeManager()->RegisterInstance(pointCloudName, context.PointCloud);		
	}	
	
	return true;
}

//----------------------------------------------------------------------------------------------
/*std::map<std::string, std::string> ImportModelsForTraining(std::string p_strFilename)
{
	std::map<std::string, std::string> models;
	
	// Use filename as the default object name
	boost::filesystem::path geometryPath(p_strFilename);	
	
	// Open wavefront file
	std::ifstream wavefrontFile;
	wavefrontFile.open(p_strFilename.c_str());
	
	if (!wavefrontFile.is_open())
	{
		std::cerr << "Error : Couldn't open file '" << p_strFilename << "'" << std::endl;
		exit(-1);
	}

	return models;
}*/

//----------------------------------------------------------------------------------------------
bool PointCloudSceneLoader::Export(const std::string &p_strFilename, unsigned int p_uiGeneralFlags, ArgumentMap* p_pArgumentMap)
{
	return true;
}
//----------------------------------------------------------------------------------------------
bool PointCloudSceneLoader::LoadBLABPoints(const std::string &p_strFilename, PointCloudContext &p_context, float p_min_dist, float p_max_dist, float p_radius, float p_scale, float p_curvature, float p_cornerRatioEpsilon, 
										 int p_kNNType, int p_kNNFlood, float p_kNNTypeRadius, float p_kNNFloodRadius, int p_kNNTypeMode, int p_kNNFloodMode, int p_edgeCornerDetect, float p_noise, float p_coplanarDst)
{
	std::ifstream input(p_strFilename.c_str(), std::fstream::binary) ;
	if(input.fail()) {
		std::cout << "[BLAB Loader] Could not open file " << p_strFilename << std::endl;
		return false;
	}

	p_context.ObjectName = p_strFilename;
	p_context.PointCloud = new KDTreePointCloud(p_context.ObjectName);
	p_context.PointCloud->SetWorldType(1);
	p_context.PointCloud->SetSurfaceCurvature(p_curvature);
	p_context.PointCloud->SetkNNType(p_kNNType);
	p_context.PointCloud->SetkNNFlood(p_kNNFlood);
	p_context.PointCloud->SetkNNFloodRadius(p_kNNFloodRadius);
	p_context.PointCloud->SetkNNTypeRadius(p_kNNTypeRadius);
	p_context.PointCloud->SetCornerRatioEpsilon(p_cornerRatioEpsilon);
	p_context.PointCloud->SetEdgeCornerDetect(p_edgeCornerDetect);
	p_context.PointCloud->SetkNNFloodMode(p_kNNFloodMode);
	p_context.PointCloud->SetkNNTypeMode(p_kNNTypeMode);
	p_context.PointCloud->SetNoise(p_noise);
	p_context.PointCloud->SetRadius(p_radius);
	p_context.PointCloud->SetRadius2(p_radius);
	p_context.PointCloud->SetMinDist(p_min_dist);
	p_context.PointCloud->SetMaxDist(p_max_dist);
	p_context.PointCloud->SetToScan(false);
	p_context.PointCloud->SetTrunk(p_strFilename);
	p_context.PointCloud->SetCoplanarDst(p_coplanarDst);

	int float_size = sizeof(float);
	int int_size = sizeof(int);

	int num_points = 0;
	input.read((char*)&num_points, int_size); 

	float* data = new float[num_points * 10]; // 10 coords per point.
	input.read((char*)data, num_points * 10 * float_size); 	

	std::cout << "******Applying Scale to Input Scene :: " << p_scale << std::endl; 
	for (int i=0; i<num_points; ++i) p_context.PointCloud->AddPoint(CloudPoint(data[i*10]*p_scale, data[i*10+1]*p_scale, data[i*10+2]*p_scale));	
	p_context.PointCloud->ComputeBoundingVolume();
	Vector3 aabbCentre = p_context.PointCloud->GetBoundingVolume()->GetCentre();
	for (int i=0; i<num_points; ++i) p_context.PointCloud->m_pointList[i].m_vertex.Position -= aabbCentre;
	
	delete [] data;
		
	return true;
}
//----------------------------------------------------------------------------------------------
bool PointCloudSceneLoader::LoadOBJGeometry(const std::string &p_strFilename, PointCloudContext &p_context, float p_min_dist, float p_max_dist, float p_radius, float p_scale, float p_curvature, float p_cornerRatioEpsilon, 
										 int p_kNNType, int p_kNNFlood, float p_kNNTypeRadius, float p_kNNFloodRadius, int p_kNNTypeMode, int p_kNNFloodMode, int p_edgeCornerDetect, float p_noise)
{
	p_context.ObjectName = p_strFilename;
	p_context.PointCloud = new KDTreePointCloud(p_context.ObjectName);
	p_context.PointCloud->SetWorldType(1);
	p_context.PointCloud->SetSurfaceCurvature(p_curvature);
	p_context.PointCloud->SetkNNType(p_kNNType);
	p_context.PointCloud->SetkNNFlood(p_kNNFlood);
	p_context.PointCloud->SetkNNFloodRadius(p_kNNFloodRadius);
	p_context.PointCloud->SetkNNTypeRadius(p_kNNTypeRadius);
	p_context.PointCloud->SetCornerRatioEpsilon(p_cornerRatioEpsilon);
	p_context.PointCloud->SetEdgeCornerDetect(p_edgeCornerDetect);
	p_context.PointCloud->SetkNNFloodMode(p_kNNFloodMode);
	p_context.PointCloud->SetkNNTypeMode(p_kNNTypeMode);
	p_context.PointCloud->SetNoise(p_noise);
	p_context.PointCloud->SetRadius2(p_radius);
	p_context.PointCloud->SetMinDist(p_min_dist);
	p_context.PointCloud->SetMaxDist(p_max_dist);
	p_context.PointCloud->SetToScan(false);
	p_context.PointCloud->SetTrunk(p_strFilename);

	/* initialize random seed for object selection */
	srand ( time(NULL) );
	
	PlanarWorldShapeForge::CreateFromOBJFile(p_strFilename, m_pEnvironment, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale);	

	std::cout << "[PointCloudSceneLoader] Generated PWPointCloud. #points=" << p_context.PointCloud->GetSize() << std::endl;		
	return true;	
}
//----------------------------------------------------------------------------------------------
bool PointCloudSceneLoader::LoadOBJGeometry(const std::string &p_strFilename, PointCloudContext &p_context, float p_min_dist, float p_max_dist, float p_radius, float p_scale, float p_curvature, float p_cornerRatioEpsilon, 
										 int p_kNNType, int p_kNNFlood, float p_kNNTypeRadius, float p_kNNFloodRadius, int p_kNNTypeMode, int p_kNNFloodMode, int p_edgeCornerDetect, float p_noise, int p_scans)
{
	p_context.ObjectName = p_strFilename;
	p_context.PointCloud = new KDTreePointCloud(p_context.ObjectName);
	p_context.PointCloud->SetWorldType(1);
	p_context.PointCloud->SetSurfaceCurvature(p_curvature);
	p_context.PointCloud->SetkNNType(p_kNNType);
	p_context.PointCloud->SetkNNFlood(p_kNNFlood);
	p_context.PointCloud->SetkNNFloodRadius(p_kNNFloodRadius);
	p_context.PointCloud->SetkNNTypeRadius(p_kNNTypeRadius);
	p_context.PointCloud->SetCornerRatioEpsilon(p_cornerRatioEpsilon);
	p_context.PointCloud->SetEdgeCornerDetect(p_edgeCornerDetect);
	p_context.PointCloud->SetkNNFloodMode(p_kNNFloodMode);
	p_context.PointCloud->SetkNNTypeMode(p_kNNTypeMode);
	p_context.PointCloud->SetNoise(p_noise);
	p_context.PointCloud->SetRadius2(p_radius);
	p_context.PointCloud->SetMinDist(p_min_dist);
	p_context.PointCloud->SetMaxDist(p_max_dist);
	p_context.PointCloud->SetTrunk(p_strFilename);
	p_context.PointCloud->SetToScan(true);
	p_context.PointCloud->SetNumberOfScans(p_scans);
	p_context.PointCloud->SetTrunk(p_strFilename);

	/* initialize random seed for object selection */
	srand ( time(NULL) );
	
	//PlanarWorldShapeForge::CreateUsingScannerFromOBJFile(p_strFilename, m_pEnvironment, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale, p_scans);

	std::cout << "[PointCloudSceneLoader] Generated PWPointCloud with no points. #points=" << p_context.PointCloud->GetSize() << std::endl;		
	return true;	
}
//----------------------------------------------------------------------------------------------

bool PointCloudSceneLoader::LoadPCSGeometry(const std::string &p_strFilename, PointCloudContext &p_context, float p_min_dist, float p_max_dist, float p_radius, float p_scale, float p_curvature, float p_cornerRatioEpsilon, 
										 int p_kNNType, int p_kNNFlood, float p_kNNTypeRadius, float p_kNNFloodRadius, int p_kNNTypeMode, int p_kNNFloodMode, int p_edgeCornerDetect, float p_noise, float p_coplanarDst)
{
	// Use filename as the default object name
	boost::filesystem::path geometryPath(p_strFilename);
	p_context.ObjectName = geometryPath.filename().string();
		
	p_context.PointCloud = new KDTreePointCloud(p_context.ObjectName);
	p_context.PointCloud->SetWorldType(1);
	p_context.PointCloud->SetSurfaceCurvature(p_curvature);
	p_context.PointCloud->SetkNNType(p_kNNType);
	p_context.PointCloud->SetkNNFlood(p_kNNFlood);
	p_context.PointCloud->SetkNNFloodRadius(p_kNNFloodRadius);
	p_context.PointCloud->SetkNNTypeRadius(p_kNNTypeRadius);
	p_context.PointCloud->SetCornerRatioEpsilon(p_cornerRatioEpsilon);
	p_context.PointCloud->SetEdgeCornerDetect(p_edgeCornerDetect);
	p_context.PointCloud->SetkNNFloodMode(p_kNNFloodMode);
	p_context.PointCloud->SetkNNTypeMode(p_kNNTypeMode);
	p_context.PointCloud->SetToScan(false);
	p_context.PointCloud->SetNoise(p_noise);	
	p_context.PointCloud->SetTrunk(p_strFilename);
	p_context.PointCloud->SetMinDist(p_min_dist);
	p_context.PointCloud->SetMaxDist(p_max_dist);
	p_context.PointCloud->SetCoplanarDst(p_coplanarDst);

	// Open .pcs file
	boost::filesystem::path p (p_strFilename, boost::filesystem::native);
	if ( !boost::filesystem::exists( p ) )
	{
		std::cerr << "Error : Couldn't open file '" << p_strFilename << "'" << std::endl;
		exit(-1);
	}
		
	//we assume all points fit in main memory
	boost::interprocess::file_mapping m_file;		
	boost::interprocess::mapped_region *m_region;	
	float * r_addr;									
	
	const char * filename = p_strFilename.c_str();
	m_file = boost::interprocess::file_mapping(filename, boost::interprocess::read_only);
	m_region = new boost::interprocess::mapped_region(m_file, boost::interprocess::read_only);					
	r_addr = (float*)m_region->get_address();
	size_t r_size = m_region->get_size();					
	size_t p_size = r_size / (3 *sizeof(float));		
	VertexP nxtvrtx;	
	int idx = 0;
	std::cout << "****Applying Scale::" << p_scale << std::endl;
	for (int i = 0; i<p_size; i++) 
	{		
		nxtvrtx.Position.Set(r_addr[idx] * p_scale, r_addr[idx+1] * p_scale, r_addr[idx+2] * p_scale);
		p_context.PointCloud->AddPoint(CloudPoint(nxtvrtx, 0, 0, -1));
		idx=idx+3;						
	}

	std::cout << "[PointCloudSceneLoader] Loaded All Points. Size=" << r_size << " #points=" << p_size << std::endl;		
	return true;	
}
//----------------------------------------------------------------------------------------------

bool PointCloudSceneLoader::LoadASCGeometry(const std::string &p_strFilename, PointCloudContext &p_context, float p_min_dist, float p_max_dist, float p_radius, float p_scale, float p_curvature, float p_cornerRatioEpsilon, 
										 int p_kNNType, int p_kNNFlood, float p_kNNTypeRadius, float p_kNNFloodRadius, int p_kNNTypeMode, int p_kNNFloodMode, int p_edgeCornerDetect, float p_noise, float p_coplanarDst)
{
	// Use filename as the default object name
	boost::filesystem::path geometryPath(p_strFilename);
	p_context.ObjectName = geometryPath.filename().string();
		
	p_context.PointCloud = new KDTreePointCloud(p_context.ObjectName);
	p_context.PointCloud->SetWorldType(1);
	p_context.PointCloud->SetSurfaceCurvature(p_curvature);
	p_context.PointCloud->SetkNNType(p_kNNType);
	p_context.PointCloud->SetkNNFlood(p_kNNFlood);
	p_context.PointCloud->SetkNNFloodRadius(p_kNNFloodRadius);
	p_context.PointCloud->SetkNNTypeRadius(p_kNNTypeRadius);
	p_context.PointCloud->SetCornerRatioEpsilon(p_cornerRatioEpsilon);
	p_context.PointCloud->SetEdgeCornerDetect(p_edgeCornerDetect);
	p_context.PointCloud->SetkNNFloodMode(p_kNNFloodMode);
	p_context.PointCloud->SetkNNTypeMode(p_kNNTypeMode);
	p_context.PointCloud->SetToScan(false);
	p_context.PointCloud->SetNoise(p_noise);	
	p_context.PointCloud->SetTrunk(p_strFilename);
	p_context.PointCloud->SetMinDist(p_min_dist);
	p_context.PointCloud->SetMaxDist(p_max_dist);
	p_context.PointCloud->SetCoplanarDst(p_coplanarDst);
	

	std::string line; 
	std::ifstream pointFile;
	pointFile.open(p_strFilename.c_str(), std::ios::binary);
	char separator;
	float pos_x, pos_y, pos_z;
	VertexP nxtvrtx;

	while(std::getline(pointFile, line))
	{		
		std::stringstream tokenStream(line);		
		tokenStream >> pos_x >> pos_y >> pos_z >> separator;
		nxtvrtx.Position.Set(pos_x * p_scale, pos_y * p_scale, pos_z * p_scale);
		p_context.PointCloud->AddPoint(CloudPoint(nxtvrtx, 0, 0, -1));
	}

	pointFile.close();
	std::cout << "[PointCloudSceneLoader] Loaded All Points. #points=" << p_context.PointCloud->GetSize() << std::endl;		
	return true;	
}
//----------------------------------------------------------------------------------------------

bool PointCloudSceneLoader::GenerateLWPCGeometry(PointCloudContext &p_context, float p_density, float p_radius, float p_scale, int p_surfaces, 
												 int p_kNNType, int p_kNNFlood, float p_kNNTypeRadius, float p_kNNFloodRadius)
{
	p_context.ObjectName = "LWPC";
	p_context.PointCloud = new KDTreePointCloud(p_context.ObjectName);
	p_context.PointCloud->SetWorldType(0);
	p_context.PointCloud->SetToScan(false);
	p_context.PointCloud->SetkNNType(p_kNNType);
	p_context.PointCloud->SetkNNFlood(p_kNNFlood);	
	p_context.PointCloud->SetkNNFloodRadius(p_kNNFloodRadius);
	p_context.PointCloud->SetkNNTypeRadius(p_kNNTypeRadius);	

	/* initialize random seed for object selection */
	srand ( time(NULL) );

	//LineWorldShapeForge::CreateDiagonal(Vector3(0.f, 0.f, 0.f), 15.f, &p_context.PointCloud->m_pointList, p_density, p_radius);
	
	//LineWorldShapeForge::CreateStairs(Vector3(-6.0f, 2.0f, 6.0f), 4.f, 4, &p_context.PointCloud->m_pointList, p_density, p_radius);

	//LineWorldShapeForge::CreateStairsWithObjects(Vector3(-6.0f, 2.0f, 6.0f), 4.f, 4, &p_context.PointCloud->m_pointList, p_density, p_radius);
	//LineWorldShapeForge::CreateStairsWithObjects(Vector3(-10.0f, -6.0f, 0.0f), 2.5f, 8, &p_context.PointCloud->m_pointList, p_density, p_radius);

	//LineWorldShapeForge::CreateSurface(Vector3(0.f, -8.f, -2.f), 15.f, &p_context.PointCloud->m_pointList, p_density, p_radius);  
	LineWorldShapeForge::CreateChair(Vector3(-4.f, -8.f, -2.f), &p_context.PointCloud->m_pointList, p_density, p_radius, 0.8f);
	//LineWorldShapeForge::CreateTable(Vector3(0.f, -8.f, -2.0f), &p_context.PointCloud->m_pointList, p_density, p_radius, 1.2f);
	//LineWorldShapeForge::CreateChair(Vector3(3.f, -8.0f, -2.0f), &p_context.PointCloud->m_pointList, p_density, p_radius, 0.4f);
	

	/*LineWorldShapeForge::CreateSurface(Vector3(3.0f, -3.0f, -2.0f), 15.f, &p_context.PointCloud->m_pointList, p_density, p_radius);  
	LineWorldShapeForge::CreateChair(Vector3(3.0f, -3.0f, -2.0f), &p_context.PointCloud->m_pointList, p_density, p_radius, 0.8f);
	LineWorldShapeForge::CreateTable(Vector3(6.0f, -3.0f, -2.0f), &p_context.PointCloud->m_pointList, p_density, p_radius, 1.2f);
	LineWorldShapeForge::CreateChair(Vector3(0.0f, -3.0f, -2.0f), &p_context.PointCloud->m_pointList, p_density, p_radius, 0.4f);
	*/
	std::cout << "[PointCloudSceneLoader] Generated LWPointCloud. #points=" << p_context.PointCloud->GetSize() << std::endl;		
	return true;	
}
//----------------------------------------------------------------------------------------------

bool PointCloudSceneLoader::GeneratePWPCGeometry(PointCloudContext &p_context, float p_min_dist, float p_max_dist, float p_radius, float p_scale, int p_surfaces, float p_curvature, 
												 float p_cornerRatioEpsilon, int p_kNNType, int p_kNNFlood, float p_kNNTypeRadius, float p_kNNFloodRadius, int p_kNNTypeMode, 
												 int p_kNNFloodMode, int p_edgeCornerDetect, float p_noise)
{
	p_context.ObjectName = "PWPC";
	p_context.PointCloud = new KDTreePointCloud(p_context.ObjectName);
	p_context.PointCloud->SetWorldType(1);
	p_context.PointCloud->SetSurfaceCurvature(p_curvature);
	p_context.PointCloud->SetkNNType(p_kNNType);
	p_context.PointCloud->SetkNNFlood(p_kNNFlood);
	p_context.PointCloud->SetkNNFloodRadius(p_kNNFloodRadius);
	p_context.PointCloud->SetkNNTypeRadius(p_kNNTypeRadius);
	p_context.PointCloud->SetCornerRatioEpsilon(p_cornerRatioEpsilon);
	p_context.PointCloud->SetEdgeCornerDetect(p_edgeCornerDetect);
	p_context.PointCloud->SetkNNFloodMode(p_kNNFloodMode);
	p_context.PointCloud->SetkNNTypeMode(p_kNNTypeMode);
	p_context.PointCloud->SetNoise(p_noise);
	p_context.PointCloud->SetToScan(false);

	/* initialize random seed for object selection */
	srand ( time(NULL) );
	
	//PlanarWorldShapeForge::CreateSurface(Vector3(-3,0,0), Vector3::UnitXNeg, 2, 3, 0, &p_context.PointCloud->m_pointList, p_density, p_radius);
	//PlanarWorldShapeForge::CreateCornellBox(Vector3(0,0,0), 10.0f, 10.0f, 10.0f, 0, &p_context.PointCloud->m_pointList, p_density, p_radius, p_scale);
	//PlanarWorldShapeForge::CreateBox(Vector3(3,-2.5,0), Vector3(0,1,0), Vector3(1,0,0), Vector3(0,0,1), 1.0f, 1.0f, 5, 0, &p_context.PointCloud->m_pointList, p_density, p_radius);
	//PlanarWorldShapeForge::CreateBox(Vector3(-2.7,-2.5,0), Vector3(0,1,0), Vector3(1,0,0), Vector3(0,0,1), 1.0f, 1.0f, 5, 0, &p_context.PointCloud->m_pointList, p_density, p_radius);
	PlanarWorldShapeForge::CreateStairs(Vector3(0,0,0), Vector3(1,0,1), Vector3(0,1,0), 5, 3, 2, 10, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale );
	//PlanarWorldShapeForge::CreateBox(Vector3(0,0,0), Vector3(0,1,0), Vector3(1,0,0), Vector3(0,0,1), 2.5f, 2.5f, 6.f, 0, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale); 															
	//PlanarWorldShapeForge::CreateChair(Vector3(0,0,0), Vector3(0,1,0), Vector3(1,0,0), 5, 3, 3, 5, &p_context.PointCloud->m_pointList, p_density, p_radius);
	
	//PlanarWorldShapeForge::CreateFromOBJFile("Model\\cornellbox\\cornellbox.obj", m_pEnvironment, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale );
	//PlanarWorldShapeForge::CreateFromOBJFile("Model\\conference\\conference.obj", m_pEnvironment, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale);
	//PlanarWorldShapeForge::CreateFromOBJFile("Model\\chairs\\chair2_ml.obj", m_pEnvironment, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale);
	//PlanarWorldShapeForge::CreateFromOBJFile("Model\\tarxien\\TarxienMerged_accu300K.obj", m_pEnvironment, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale);
	//PlanarWorldShapeForge::CreateFromOBJFile("Model\\sibenik\\sibenik.obj", m_pEnvironment, &p_context.PointCloud->m_pointList, p_min_dist, p_max_dist, p_radius, p_scale);	

	std::cout << "[PointCloudSceneLoader] Generated PWPointCloud. #points=" << p_context.PointCloud->GetSize() << std::endl;		
	return true;	
}
//----------------------------------------------------------------------------------------------